﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.TextMining.Collapse
{
    /// <summary>
    /// 
    /// </summary>
    public partial class EntityLinkEditor : Form, IComponentEditor
    {
        private object _ActivityNode;
        private EntityLinkComponent _Linker;

        /// <summary>
        /// 
        /// </summary>
        public EntityLinkEditor()
        {
            InitializeComponent();
        }

        private void EntityLinkEditor_Load(object sender, EventArgs e)
        {

        }

        #region Implementation of IComponentEditor

        public event UpdateComponentSettings UpdateComponentSettingEvent;

        /// <summary></summary>
        public object OwnerActivityNode
        {
            get { return _ActivityNode;}
            set { _ActivityNode = value;}
        }

        /// <summary></summary>
        public Type WorkflowComponentType
        {
            get { return typeof (EntityLinkComponent); }
        }

        /// <summary></summary>
        public void LoadSettings(GlobalVariable[] globalVars, WorkflowComponentBase[] fromComponents, object activityNode, WorkflowComponentBase wfComponent)
        {
            this._ActivityNode = activityNode;
            this._Linker = (EntityLinkComponent) wfComponent;

            this.txt_ConnStr1.Text = this._Linker.ConnStr1;
            this.txt_Schema1.Text = this._Linker.SchemaName1;
            this.PopulateTables(this._Linker.ConnStr1, this._Linker.SchemaName1, this.cbo_Table1);
            this.SelectComboxValue(this.cbo_Table1, this._Linker.TableName1);
            this.rt_SQL1.Text = this._Linker.Sql1;
            TableColumn[] cols1 = this.GetEntityFields(
                this._Linker.ConnStr1, this._Linker.SchemaName1,
                this._Linker.TableName1, this._Linker.Sql1);
            this.cbo_PK1.Items.Clear();
            if(cols1 !=null && cols1.Length>0)
            {
                foreach(TableColumn col in cols1)
                {
                    this.cbo_PK1.Items.Add(col.ColumnName);
                }
            }
            this.SelectComboxValue(this.cbo_PK1, this._Linker.PKField1);
            this.txt_Conn2.Text = this._Linker.ConnStr2;
            this.txt_Schema2.Text = this._Linker.SchemaName2;
            this.PopulateTables(this._Linker.ConnStr2, this._Linker.SchemaName2, this.cbo_Table2);
            this.SelectComboxValue(this.cbo_Table2, this._Linker.TableName2);
            this.rt_SQL2.Text = this._Linker.Sql2;
            TableColumn[] cols2 = this.GetEntityFields(
                this._Linker.ConnStr2, this._Linker.SchemaName2,
                this._Linker.TableName2, this._Linker.Sql2);
            this.cbo_PK2.Items.Clear();
            if(cols2 !=null && cols2.Length>0)
            {
                foreach(TableColumn col in cols2)
                {
                    this.cbo_PK2.Items.Add(col.ColumnName);
                }
            }
            this.SelectComboxValue(this.cbo_PK2,this._Linker.PKField2);
            this.dv_Comparers.Rows.Clear();
            List<IAttributeComparer> comparers = new List<IAttributeComparer>();
            Assembly assembly = this.GetType().Assembly;
            Type[] types = assembly.GetTypes();
            foreach(Type type in types)
            {
                if(type.GetInterface(typeof(IAttributeComparer).FullName)!=null)
                {
                    IAttributeComparer comparer = (IAttributeComparer) Activator.CreateInstance(type);
                    comparers.Add(comparer);
                }
            }
            if (cols1 != null && cols1.Length > 0)
            {
                foreach (TableColumn col1 in cols1)
                {
                    DataGridViewRow dr = new DataGridViewRow();
                    DataGridViewCheckBoxCell cellSelect=new DataGridViewCheckBoxCell();
                    if(this._Linker.DescFields1 !=null && this._Linker.DescFields1.Contains(col1.ColumnName))
                        cellSelect.Value = true;
                    else if(this._Linker.AssocFields1 !=null && this._Linker.AssocFields1.Contains(col1.ColumnName))
                        cellSelect.Value = true;
                    else
                        cellSelect.Value = false;
                    dr.Cells.Add(cellSelect);
                    DataGridViewTextBoxCell cellField1=new DataGridViewTextBoxCell();
                    cellField1.Value = col1.ColumnName;
                    dr.Cells.Add(cellField1);
                    DataGridViewImageCell cellTx1=new DataGridViewImageCell();
                    cellTx1.Value = this.imageList1.Images[0];
                    if (this._Linker.FieldTransformations1 != null && this._Linker.FieldTransformations1.ContainsKey(col1.ColumnName))
                        cellTx1.Value = this.imageList1.Images[1];
                    dr.Cells.Add(cellTx1);
                    DataGridViewCheckBoxCell cellAssoc=new DataGridViewCheckBoxCell();
                    cellAssoc.Value = false;
                    if(this._Linker.AssocFields1!=null && this._Linker.AssocFields1.Contains(col1.ColumnName))
                        cellAssoc.Value = true;
                    dr.Cells.Add(cellAssoc);
                    DataGridViewComboBoxCell cellField2=new DataGridViewComboBoxCell();
                    if(cols2 !=null && cols2.Length>0)
                    {
                        foreach(TableColumn col2 in cols2)
                        {
                            cellField2.Items.Add(col2.ColumnName);
                        }
                    }
                    string field2 = string.Empty;
                    if (this._Linker.Field1_Field2_Mappings != null && this._Linker.Field1_Field2_Mappings.ContainsKey(col1.ColumnName))
                    {
                        field2 = this._Linker.Field1_Field2_Mappings[col1.ColumnName];
                        cellField2.Value = field2;
                    }
                    dr.Cells.Add(cellField2);
                    DataGridViewImageCell cellTx2=new DataGridViewImageCell();
                    cellTx2.Value = this.imageList1.Images[0];
                    if (this._Linker.FieldTransformations2 != null && this._Linker.FieldTransformations2.ContainsKey(field2))
                        cellTx2.Value = this.imageList1.Images[1];
                    dr.Cells.Add(cellTx2);
                    DataGridViewComboBoxCell cellComparer=new DataGridViewComboBoxCell();
                    if(comparers !=null && comparers.Count>0)
                    {
                        foreach(IAttributeComparer comparer in comparers)
                        {
                            cellComparer.Items.Add(comparer.GetType().FullName);
                        }
                    }
                    if (this._Linker.FieldComparers != null && this._Linker.FieldComparers.ContainsKey(col1.ColumnName))
                        cellComparer.Value = this._Linker.FieldComparers[col1.ColumnName];
                    dr.Cells.Add(cellComparer);
                    DataGridViewTextBoxCell cellWeight=new DataGridViewTextBoxCell();
                    cellWeight.Value = 0;
                    if (this._Linker.FieldWeights != null && this._Linker.FieldWeights.ContainsKey(col1.ColumnName))
                        cellWeight.Value = this._Linker.FieldWeights[col1.ColumnName];
                    dr.Cells.Add(cellWeight);
                    DataGridViewTextBoxCell cellPenalty=new DataGridViewTextBoxCell();
                    cellPenalty.Value = 0;
                    if (this._Linker.FieldPenalties != null && this._Linker.FieldPenalties.ContainsKey(col1.ColumnName))
                        cellPenalty.Value = this._Linker.FieldPenalties[col1.ColumnName];
                    dr.Cells.Add(cellPenalty);
                    DataGridViewTextBoxCell cellTransform1=new DataGridViewTextBoxCell();
                    cellTransform1.Value = string.Empty;
                    if (this._Linker.FieldTransformations1 != null && this._Linker.FieldTransformations1.ContainsKey(col1.ColumnName))
                        cellTransform1.Value = this._Linker.FieldTransformations1[col1.ColumnName];
                    dr.Cells.Add(cellTransform1);
                    DataGridViewTextBoxCell cellTransform2=new DataGridViewTextBoxCell();
                    cellTransform2.Value = string.Empty;
                    if (this._Linker.FieldTransformations2 != null && this._Linker.FieldTransformations2.ContainsKey(field2))
                        cellTransform2.Value = this._Linker.FieldTransformations2[field2];
                    dr.Cells.Add(cellTransform2);
                    

                    this.dv_Comparers.Rows.Add(dr);
                }
            }

            this.num_Assoc.Value =(decimal) this._Linker.AssocThreshold;
            this.num_Link.Value = (decimal) this._Linker.LinkThreshold;

            this.txt_OutputTable.Text = this._Linker.OutputTableName;
            this.txt_EntityIDFIeld1.Text = this._Linker.EntityIDField1;
            this.txt_EntityIDField2.Text = this._Linker.EntityIDField2;
        }

        

        /// <summary></summary>
        public void SaveSettings()
        {
            this._Linker.ConnStr1 = this.txt_ConnStr1.Text;
            this._Linker.SchemaName1 = this.txt_Schema1.Text;
            this._Linker.TableName1 = this.cbo_Table1.Text;
            this._Linker.Sql1 = this.rt_SQL1.Text;
            this._Linker.PKField1 = this.cbo_PK1.Text;
            this._Linker.DescFields1=new List<string>();
            this._Linker.AssocFields1=new List<string>();
            this._Linker.FieldTransformations1=new Dictionary<string, string>();

            this._Linker.ConnStr2 = this.txt_Conn2.Text;
            this._Linker.SchemaName2 = this.txt_Schema2.Text;
            this._Linker.TableName2 = this.cbo_Table2.Text;
            this._Linker.Sql2 = this.rt_SQL2.Text;
            this._Linker.PKField2 = this.cbo_PK2.Text;
            this._Linker.DescFields2 = new List<string>();
            this._Linker.AssocFields2 = new List<string>();
            this._Linker.FieldTransformations2 = new Dictionary<string, string>();

            this._Linker.Field1_Field2_Mappings=new Dictionary<string, string>();
            this._Linker.FieldWeights=new Dictionary<string, double>();
            this._Linker.FieldPenalties=new Dictionary<string, double>();
            this._Linker.FieldComparers=new Dictionary<string, string>();
            foreach(DataGridViewRow dr in this.dv_Comparers.Rows)
            {
                if(!dr.IsNewRow && dr.Cells[0].Value!=null && 
                    dr.Cells[1].Value !=null && dr.Cells[2].Value !=null)
                {
                    bool select = bool.Parse(dr.Cells[0].Value.ToString());
                    if(!select)
                        continue;
                    string field1 = dr.Cells[1].Value.ToString();
                    bool assoc =bool.Parse(dr.Cells[3].Value.ToString());
                    if(assoc)
                        this._Linker.AssocFields1.Add(field1);
                    else 
                        this._Linker.DescFields1.Add(field1);
                    string field2 = dr.Cells[4].Value.ToString();
                    this._Linker.Field1_Field2_Mappings.Add(field1, field2);
                    if (assoc)
                        this._Linker.AssocFields2.Add(field2);
                    else
                        this._Linker.DescFields2.Add(field2);
                    string comparerName = dr.Cells[6].Value.ToString();
                    this._Linker.FieldComparers.Add(field1, comparerName);

                    double weight = double.Parse(dr.Cells[7].Value.ToString());
                    this._Linker.FieldWeights.Add(field1, weight);
                    
                    double penalty = double.Parse(dr.Cells[8].Value.ToString());
                    this._Linker.FieldPenalties.Add(field1, penalty);

                    string code1 = dr.Cells[9].Value.ToString();
                    if(!string.IsNullOrEmpty(code1))
                        this._Linker.FieldTransformations1.Add(field1,code1);
                    string code2 = dr.Cells[10].Value.ToString();
                    if (!string.IsNullOrEmpty(code2))
                        this._Linker.FieldTransformations2.Add(field2, code2);
                    
                }
            }
            this._Linker.AssocThreshold = (double) this.num_Assoc.Value;
            this._Linker.LinkThreshold = (double) this.num_Link.Value;

            this._Linker.OutputTableName = this.txt_OutputTable.Text;
            this._Linker.EntityIDField1 = this.txt_EntityIDFIeld1.Text;
            this._Linker.EntityIDField2 = this.txt_EntityIDField2.Text;
        }

        /// <summary></summary>
        public TestResult Test()
        {
            throw new System.NotImplementedException();
        }

        #endregion

        private void btn_OK_Click(object sender, EventArgs e)
        {
            try
            {
                this.SaveSettings();
                if (this.UpdateComponentSettingEvent != null)
                    this.UpdateComponentSettingEvent(this._ActivityNode, this._Linker);
                this.Close();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btn_GetTables1_Click(object sender, EventArgs e)
        {
            this.PopulateTables(this.txt_ConnStr1.Text,this.txt_Schema1.Text,this.cbo_Table1);
        }

        private void btn_GetTables2_Click(object sender, EventArgs e)
        {
            this.PopulateTables(this.txt_Conn2.Text,this.txt_Schema2.Text,this.cbo_Table2);
        }

        private void btn_Refresh1_Click(object sender, EventArgs e)
        {
            this.PopulateEntityFields();
        }

        private void btn_Refresh2_Click(object sender, EventArgs e)
        {
            this.PopulateEntityFields();
        }

        private void PopulateEntityFields()
        {
            this.cbo_PK1.Items.Clear();
            TableColumn[] cols1 = this.GetEntityFields(
                this.txt_ConnStr1.Text, this.txt_Schema1.Text,
                this.cbo_Table1.Text, this.rt_SQL1.Text);
            if (cols1 != null && cols1.Length > 0)
            {
                foreach (TableColumn col in cols1)
                {
                    this.cbo_PK1.Items.Add(col.ColumnName);
                }
            }
            this.SelectComboxValue(this.cbo_PK1, this._Linker.PKField1);

            this.cbo_PK2.Items.Clear();
            TableColumn[] cols2 = this.GetEntityFields(
                this.txt_Conn2.Text, this.txt_Schema2.Text,
                this.cbo_Table2.Text, this.rt_SQL2.Text);
            if(cols2 !=null && cols2.Length>0)
            {
                foreach(TableColumn col in cols2)
                {
                    this.cbo_PK2.Items.Add(col.ColumnName);
                }
            }
            this.SelectComboxValue(this.cbo_PK2,this._Linker.PKField2);

            List<IAttributeComparer> comparers = new List<IAttributeComparer>();
            Assembly assembly = this.GetType().Assembly;
            Type[] types = assembly.GetTypes();
            foreach (Type type in types)
            {
                if (type.GetInterface(typeof(IAttributeComparer).FullName) != null)
                {
                    IAttributeComparer comparer = (IAttributeComparer)Activator.CreateInstance(type);
                    comparers.Add(comparer);
                }
            }
            this.dv_Comparers.Rows.Clear();
            foreach(TableColumn col1 in cols1)
            {
                DataGridViewRow dr=new DataGridViewRow();
                DataGridViewCheckBoxCell cellSelect = new DataGridViewCheckBoxCell();
                if (this._Linker.DescFields1 != null && this._Linker.DescFields1.Contains(col1.ColumnName))
                    cellSelect.Value = true;
                else if (this._Linker.AssocFields1 != null && this._Linker.AssocFields1.Contains(col1.ColumnName))
                    cellSelect.Value = true;
                else
                    cellSelect.Value = false;
                dr.Cells.Add(cellSelect);
                DataGridViewTextBoxCell cellField1 = new DataGridViewTextBoxCell();
                cellField1.Value = col1.ColumnName;
                dr.Cells.Add(cellField1);
                DataGridViewImageCell cellTx1 = new DataGridViewImageCell();
                cellTx1.Value = this.imageList1.Images[0];
                if (this._Linker.FieldTransformations1 != null && this._Linker.FieldTransformations1.ContainsKey(col1.ColumnName))
                    cellTx1.Value = this.imageList1.Images[1];
                dr.Cells.Add(cellTx1);
                DataGridViewCheckBoxCell cellAssoc = new DataGridViewCheckBoxCell();
                cellAssoc.Value = false;
                if (this._Linker.AssocFields1 != null && this._Linker.AssocFields1.Contains(col1.ColumnName))
                    cellAssoc.Value = true;
                dr.Cells.Add(cellAssoc);
                DataGridViewComboBoxCell cellField2 = new DataGridViewComboBoxCell();
                if (cols2 != null && cols2.Length > 0)
                {
                    foreach (TableColumn col2 in cols2)
                    {
                        cellField2.Items.Add(col2.ColumnName);
                    }
                }
                string field2 = string.Empty;
                if (this._Linker.Field1_Field2_Mappings != null && this._Linker.Field1_Field2_Mappings.ContainsKey(col1.ColumnName))
                {
                    field2 = this._Linker.Field1_Field2_Mappings[col1.ColumnName];
                    cellField2.Value = field2;
                }
                dr.Cells.Add(cellField2);
                DataGridViewImageCell cellTx2 = new DataGridViewImageCell();
                cellTx2.Value = this.imageList1.Images[0];
                if (this._Linker.FieldTransformations2 != null && this._Linker.FieldTransformations2.ContainsKey(field2))
                    cellTx2.Value = this.imageList1.Images[1];
                dr.Cells.Add(cellTx2);
                DataGridViewComboBoxCell cellComparer = new DataGridViewComboBoxCell();
                if (comparers != null && comparers.Count > 0)
                {
                    foreach (IAttributeComparer comparer in comparers)
                    {
                        cellComparer.Items.Add(comparer.GetType().FullName);
                    }
                }
                if (this._Linker.FieldComparers != null && this._Linker.FieldComparers.ContainsKey(col1.ColumnName))
                    cellComparer.Value = this._Linker.FieldComparers[col1.ColumnName];
                dr.Cells.Add(cellComparer);
                DataGridViewTextBoxCell cellWeight = new DataGridViewTextBoxCell();
                cellWeight.Value = 0;
                if (this._Linker.FieldWeights != null && this._Linker.FieldWeights.ContainsKey(col1.ColumnName))
                    cellWeight.Value = this._Linker.FieldWeights[col1.ColumnName];
                dr.Cells.Add(cellWeight);
                DataGridViewTextBoxCell cellPenalty = new DataGridViewTextBoxCell();
                cellPenalty.Value = 0;
                if (this._Linker.FieldPenalties != null && this._Linker.FieldPenalties.ContainsKey(col1.ColumnName))
                    cellPenalty.Value = this._Linker.FieldPenalties[col1.ColumnName];
                dr.Cells.Add(cellPenalty);
                DataGridViewTextBoxCell cellTransform1 = new DataGridViewTextBoxCell();
                cellTransform1.Value = string.Empty;
                if (this._Linker.FieldTransformations1 != null && this._Linker.FieldTransformations1.ContainsKey(col1.ColumnName))
                    cellTransform1.Value = this._Linker.FieldTransformations1[col1.ColumnName];
                dr.Cells.Add(cellTransform1);
                DataGridViewTextBoxCell cellTransform2 = new DataGridViewTextBoxCell();
                cellTransform2.Value = string.Empty;
                if (this._Linker.FieldTransformations2 != null && this._Linker.FieldTransformations2.ContainsKey(field2))
                    cellTransform2.Value = this._Linker.FieldTransformations2[field2];
                dr.Cells.Add(cellTransform2);

                this.dv_Comparers.Rows.Add(dr);
            }
        }
        
        private TableColumn[] GetEntityFields(string connStr,string schema,
            string tbl, string sql)
        {
            TableColumn[] cols = null;
            if (!string.IsNullOrEmpty(sql))
                cols = DbUtil.GetTableColumns(DataProviderType.MSSQL, connStr, sql);
            else
                cols = DbUtil.GetTableColumns(DataProviderType.MSSQL, connStr, schema, tbl);
            return cols;
        }

        private void PopulateTables(string connStr, string schemaName, ComboBox cboTables)
        {
            cboTables.Items.Clear();
            string[] tbls = DbUtil.GetTableNames(DataProviderType.MSSQL, schemaName, connStr);
            if (tbls != null && tbls.Length > 0)
            {
                foreach (string tblName in tbls)
                    cboTables.Items.Add(tblName);
            }
        }

        private void SelectComboxValue(ComboBox comboBox, string name)
        {
            if (comboBox.Items.Count > 0 && !string.IsNullOrEmpty(name))
            {
                for (int i = 0; i < comboBox.Items.Count; i++)
                {
                    if (comboBox.Items[i].ToString().ToLower() == name.ToLower())
                    {
                        comboBox.SelectedIndex = i;
                        break;
                    }
                }
            }
        }

        private void btn_Compare_Click(object sender, EventArgs e)
        {
            try
            {
                this.SaveSettings();
                EntityLinkInstruction instruction = (EntityLinkInstruction)this._Linker.Instruction;
                EntityLinkWorker worker = new EntityLinkWorker();
                worker.SetInstruction(Guid.NewGuid(), instruction, "Link", "EntityLink");
                DataTable dt = worker.TestEntityLinks(this.txt_Entity1ID.Text, this.txt_Entity2ID.Text);
                this.dv_Result.DataSource = dt;
                this.dv_Result.Refresh();
                double totalScore = 0;
                if (dt != null && dt.Rows.Count > 0)
                {
                    foreach (DataRow dr in dt.Rows)
                    {
                        totalScore += double.Parse(dr["Score"].ToString());
                    }
                }
                this.lbl_Score.Text = string.Format("Total score: {0}", Math.Round(totalScore, 2));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}
